/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "sync_folder_access_n_exporter.h"

#include <tuple>

#include "cloud_disk_js_manager.h"
#include "dfs_error.h"
#include "utils_log.h"

namespace OHOS::FileManagement::CloudDiskService {
using namespace std;
using namespace LibN;
constexpr const char* PATH = "path";
constexpr const char* STATE = "state";
constexpr const char* DISPLAY_NAME_RES_ID = "displayNameResId";
constexpr const char* DISPLAY_NAME = "displayName";
constexpr const char* BUNDLE_NAME = "bundleName";

std::tuple<napi_status, napi_value> CreateSyncFolderExtList(napi_env env,
    const std::vector<SyncFolderExt> &syncFolderExts)
{
    napi_value res = nullptr;
    napi_status status = napi_ok;
    if ((status = napi_create_array(env, &res)) != napi_ok) {
        LOGE("Create array failed");
        return { status, res };
    }
    for (size_t i = 0; i < syncFolderExts.size(); ++i) {
        napi_value ele = nullptr;
        if ((napi_create_object(env, &ele)) != napi_ok) {
            LOGE("Create object failed");
            return { status, res };
        }
        if ((napi_set_named_property(
            env, ele, PATH, NVal::CreateUTF8String(env, syncFolderExts[i].path_).val_)) != napi_ok) {
            LOGE("Set named property path failed");
            return { status, res };
        }
        if ((status = napi_set_named_property(env, ele, STATE,
            NVal::CreateInt32(env, static_cast<int32_t>(syncFolderExts[i].state_)).val_)) != napi_ok) {
            LOGE("Set named property state failed");
            return { status, res };
        }
        if (syncFolderExts[i].displayNameResId_ != -1) {
            if ((status = napi_set_named_property(env, ele, DISPLAY_NAME_RES_ID,
                NVal::CreateInt32(env, syncFolderExts[i].displayNameResId_).val_)) != napi_ok) {
                LOGE("Set named property resId failed");
                return { status, res };
            }
        }
        if (!syncFolderExts[i].displayName_.empty()) {
            if ((status = napi_set_named_property(env,
                ele, DISPLAY_NAME, NVal::CreateUTF8String(env, syncFolderExts[i].displayName_).val_)) != napi_ok) {
                LOGE("Set named property displayName failed");
                return { status, res };
            }
        }
        if ((status = napi_set_named_property(env,
            ele, BUNDLE_NAME, NVal::CreateUTF8String(env, syncFolderExts[i].bundleName_).val_)) != napi_ok) {
            LOGE("Set named property bundleName failed");
            return { status, res };
        }
        if ((status = napi_set_element(env, res, i, ele)) != napi_ok) {
            LOGE("Set element failed");
            return { status, res };
        }
    }
    return { napi_ok, res };
}

SyncFolderAccessNExporter::SyncFolderAccessNExporter(napi_env env, napi_value exports): NExporter(env, exports) {}

SyncFolderAccessNExporter::~SyncFolderAccessNExporter() {};

napi_value SyncFolderAccessNExporter::GetAllSyncFolders(napi_env env, napi_callback_info cbinfo)
{
    NFuncArg funcArg(env, cbinfo);
    if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
        LOGE("Number of arguments unmatched");
        NError(ERR_INVALID_PARAM).ThrowErr(env);
        return nullptr;
    }
    auto result = std::make_shared<std::vector<SyncFolderExt>>();
    auto syncFolerJSAccess = NClass::GetEntityOf<CloudDiskJSManager>(env, funcArg.GetThisVar());
    if (!syncFolerJSAccess) {
        LOGE("GetEntityOf syncFolerJSAccess failed");
        NError(ERR_INVALID_PARAM).ThrowErr(env);
        return nullptr;
    }
    auto cbExec = [result, syncFolerJSAccess]() -> NError {
        if (!syncFolerJSAccess) {
            LOGE("syncFolerManager is nullptr");
            return NError(ERR_INTERNAL_ERROR);
        }
        int ret = syncFolerJSAccess->GetAllSyncFolders(*result);
        return NError(ret);
    };
    auto cbCompl = [result](napi_env env, NError err) -> NVal {
        if (err) {
            return {env, err.GetNapiErr(env)};
        }
        auto [succSta, syncFolderVec] = CreateSyncFolderExtList(env, *result);
        if (succSta == napi_ok) {
            return {env, syncFolderVec};
        }
        LOGE("CreateSyncFolderExtList failed");
        return {env, NError(ERR_INTERNAL_ERROR).GetNapiErr(env)};
    };
    const string procedureName = "clouddisk_getAllSyncFolders";
    NVal thisVar(env, funcArg.GetThisVar());
    return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
}

std::string SyncFolderAccessNExporter::GetClassName()
{
    return SyncFolderAccessNExporter::className_;
}

napi_value SyncFolderAccessNExporter::Constructor(napi_env env, napi_callback_info cbinfo)
{
    NFuncArg funcArg(env, cbinfo);
    if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
        LOGE("Number of arguments unmatched");
        NError(ERR_INVALID_PARAM).ThrowErr(env);
        return nullptr;
    }
    unique_ptr<CloudDiskJSManager> cloudDiskJSManager = make_unique<CloudDiskJSManager>();
    if (!NClass::SetEntityFor<CloudDiskJSManager>(env, funcArg.GetThisVar(), std::move(cloudDiskJSManager))) {
        NError(ERR_INVALID_PARAM).ThrowErr(env);
        return nullptr;
    }
    return funcArg.GetThisVar();
}

bool SyncFolderAccessNExporter::Export()
{
    vector<napi_property_descriptor> props = {
        NVal::DeclareNapiFunction("getAllSyncFolders", GetAllSyncFolders)
    };
    string className = GetClassName();
    bool succ = false;
    napi_value classValue = nullptr;
    std::tie(succ, classValue) = NClass::DefineClass(
        exports_.env_, className, SyncFolderAccessNExporter::Constructor, std::move(props));
    if (!succ) {
        LOGE("Failed to define class %{public}s", className.c_str());
        NError(ERR_INVALID_PARAM).ThrowErr(exports_.env_);
        return false;
    }
    succ = NClass::SaveClass(exports_.env_, className, classValue);
    if (!succ) {
        LOGE("Failed to save class %{public}s", className.c_str());
        NError(ERR_INVALID_PARAM).ThrowErr(exports_.env_);
        return false;
    }
    return exports_.AddProp(className, classValue);
}
} // namespace OHOS::FileManagement::CloudDiskService
